#pragma once

#include <memory>
#include "base/Bytes.h"
#include "protocol/routeinfo.pb.h"
#include "protocol/transport.pb.h"
#include "model/ClientNode.h"
#include "ProtocolCodec.h"

namespace zeroplus::mq
{
    // ---------------------- 客户端请求构建模板 ----------------------
    template <transport::RequestCode Code, typename Req, typename Resp>
    class RequestBuilder
    {
    private:
        std::shared_ptr<ClientNode> client_;

    public:
        explicit RequestBuilder(std::shared_ptr<ClientNode> client)
            : client_(client)
        {
        }

        std::tuple<transport::ResponseCode, Resp> InvokeSync(const Req &request)
        {
            // 构建请求命令
            transport::RequestCommand requestCmd;
            requestCmd.set_code(Code);
            requestCmd.set_body(ProtocolCodec<Req>::Encode(request).to_string());
            auto requestBytes = ProtocolCodec<transport::RequestCommand>::Encode(requestCmd);

            // 发送请求
            auto [responseBytes, status] = client_->InvokeSync(requestBytes);
            // 处理响应
            auto replyCmd = ProtocolCodec<transport::ReplyCommand>::Decode(responseBytes);
            if (!status)
            {
                replyCmd.set_code(transport::ResponseCode::RECV_TIMEOUT);
            }

            return std::make_tuple(replyCmd.code(), ProtocolCodec<Resp>::Decode(Bytes::from_string(replyCmd.body())));
        }

        Resp InvokeOneWay(const Req &request)
        {
            // 静态断言：如果Resp不是void，则报错
            static_assert(std::is_same<Resp, void>::value, "Resp must be void if you call InvokeOneWay");
            // 构建请求命令
            transport::RequestCommand requestCmd;
            requestCmd.set_code(Code);
            requestCmd.set_body(ProtocolCodec<Req>::Encode(request).to_string());
            auto requestBytes = ProtocolCodec<transport::RequestCommand>::Encode(requestCmd);

            // 发送请求
            client_->InvokeOneWay(requestBytes);
        }
    };
}